/*! \file coarsening.hpp
 *  \author Zhao Chengpeng (chengpeng_zhao@foxmail.com)
 *  \date 2024-01-10
 *  \brief base class for AMG coarsening method
 */

#ifndef SOLVERS_MULTIGRID_COARSENING_HPP
#define SOLVERS_MULTIGRID_COARSENING_HPP

#include "unapMatrix.hpp"
#include "unapVector.hpp"

#define IMPL_RENDER()                                                      \
  virtual void restrictField(Vector<scalar> &cf, const Vector<scalar> &ff, \
                             const label fineLevelIndex) const {           \
    restrictField_internal<scalar>(cf, ff, fineLevelIndex);                \
  }                                                                        \
  virtual void prolongField(Vector<scalar> &ff, const Vector<scalar> &cf,  \
                            const label coarseLevelIndex) const {          \
    prolongField_internal<scalar>(ff, cf, coarseLevelIndex);               \
  }

namespace UNAP {

// Simply define the types that each concrete class will use
template <typename Cmpt>
class Coarsening {
 protected:
  /// \brief communication domain
  Communicator *commcator_;
  bool noCoarse_;
  /// \brief max number of levels
  label maxLevels_;
  /// \brief number of cells in coarsest level
  label rowSizeInCoarsestLevel_;
  /// \brief the number of cells in each level
  labelVector rowSize_;
  /// \brief number of levels created
  label nCreatedLevels_;
  /// \brief number of levels to merge, 1 = don't merge, 2 = merge pairs etc.
  label mergeLevels_;

 public:
  Coarsening(Communicator *comm)
      : commcator_(comm),
        noCoarse_(false),
        maxLevels_(20),
        rowSizeInCoarsestLevel_(50),
        rowSize_(maxLevels_, comm),
        nCreatedLevels_(0),
        mergeLevels_(1) {}

  /// \brief return the number of total levels
  label size() const { return nCreatedLevels_; }
  /// \brief set the number of rows in the coarsest level
  /// \param i number of rows in the coarsest level
  void SET_rowSizeInCoarsestLevel(const label i) {
    rowSizeInCoarsestLevel_ = i;
  }

  bool ifNoCoarse() const { return noCoarse_; }

  /*! * * * * * * * * * * * * * * *  * * * * * * * * * * * * * */

  /// \brief set the maximum number of levles
  /// \param i maximum number of levles
  virtual void SET_maxLevels(const label i) {}
  virtual void compactLevels(const label nCreatedLevels) {}
  virtual const Matrix<Cmpt> &matrixLevel(const label i) const = 0;
  virtual const Matrix<Cmpt> &coarseMatrix(const label i) const = 0;

  /*! template function can not be virtual */
  virtual void restrictField(Vector<label> &cf, const Vector<label> &ff,
                             const label fineLevelIndex) const {}
  virtual void restrictField(Vector<scalar> &cf, const Vector<scalar> &ff,
                             const label fineLevelIndex) const {}
  virtual void prolongField(Vector<label> &ff, const Vector<label> &cf,
                            const label coarseLevelIndex) const {}
  virtual void prolongField(Vector<scalar> &ff, const Vector<scalar> &cf,
                            const label coarseLevelIndex) const {}

  virtual ~Coarsening() {}
};

} /* End namespace UNAP */
#endif /* end of include guard: SOLVERS_MULTIGRID_COARSENING_HPP */
